package app.meibei.com.rtspserverdemo.lprtmp;

import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaFormat;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.util.Log;

import com.cry.cry.mediaprojectioncode.sender.Sender;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;

import app.com.rtsplibrary.constants.Constant;
import app.com.rtsplibrary.hw.NV21Convertor;

/**
 * RTMP推流编码器
 * 管理MediaCodec，放入数据
 * 获取MediaCodec类用于拿取数据
 */
public class RtmpMediaCodec implements IRtmpMedia {
    private static final String TAG = "RtmpMediaCodec";
    //编码器
    public MediaCodec mediaCodec;
    private NV21Convertor convertor = new NV21Convertor();
    final int TIMEOUT_USEC = 10000;
    public volatile boolean mIsStopRequested = false;
    private Handler rtmpSendHandler = new Handler();

    public RtmpMediaCodec() {
        createEncoderThread();
    }

    private void createEncoderThread() {
        HandlerThread encoder = new HandlerThread("Encoder");
        encoder.start();
        Looper looper = encoder.getLooper();
        rtmpSendHandler = new Handler(looper);
    }

    //初始化编码器
    public void initMediaCodec() {
        MediaCodecInfo mediaCodecInfo = selectCodec(Constant.MIME_TYPE);
        if (mediaCodecInfo == null) {
            throw new RuntimeException("mediaCodecInfo is Empty");
        }
        Log.e(TAG, "MediaCodecInfo " + mediaCodecInfo.getName());
        try {
            mediaCodec = MediaCodec.createByCodecName(mediaCodecInfo.getName());
        } catch (IOException e) {
            e.printStackTrace();
        }
        MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", Constans.RTMP_WIDTH, Constans.RTMP_HEIGHT);
        int bitrate = 2 * Constans.RTMP_HEIGHT * Constans.RTMP_WIDTH * 15 / 20;
        mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
        mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 15);
        mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
        mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
        mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
        mediaCodec.start();


    }

    /**
     * 开始启动RTMP推流
     */
    @Override
    public void startRtmp(String url, int width, int height) {
        initMediaCodec();
        mIsStopRequested = false;
        Sender.getInstance().close();
        Sender.getInstance().open(url, width, height);

    }

    /**
     * 停止RTMP推流
     */
    @Override
    public void stopRtmp() {
        Sender.getInstance().close();
        mIsStopRequested = true;
        rtmpSendHandler.post(() -> {
            mediaCodec.signalEndOfInputStream();
            mediaCodec.stop();
        });
    }

    //yv12 转 yuv420p  yvu -> yuv
    private void swapYV12_2_I420(byte[] yv12bytes, byte[] i420bytes, int width, int height)
    {
        System.arraycopy(yv12bytes, 0, i420bytes, 0,width*height);
        System.arraycopy(yv12bytes, width*height+width*height/4, i420bytes, width*height,width*height/4);
        System.arraycopy(yv12bytes, width*height, i420bytes, width*height+width*height/4,width*height/4);
    }
    /**
     * 放入原始数据到编码器中编码为H.264格式
     */
    public void inputBuffer(byte[] data) {
//        final int LENGTH = Constans.RTMP_HEIGHT * Constans.RTMP_WIDTH;
//        //YV12数据转化成COLOR_FormatYUV420Planar
//        Log.i(TAG, LENGTH + "  " + (data.length - LENGTH));
//        for (int i = LENGTH; i < (LENGTH + LENGTH / 4); i++) {
//            byte temp = data[i];
//            data[i] = data[i + LENGTH / 4];
//            data[i + LENGTH / 4] = temp;
//        }
        byte[] i420=new byte[Constans.RTMP_HEIGHT*Constans.RTMP_WIDTH*3/2];
        swapYV12_2_I420(data,i420,Constans.RTMP_HEIGHT,Constans.RTMP_WIDTH);
        long now = System.nanoTime() / 1000;

        ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
        ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();


        try {

            int bufferIndex = mediaCodec.dequeueInputBuffer(-1);
//            Log.i(TAG, "inputBuffer: " + bufferIndex);
            if (bufferIndex >= 0) {
                ByteBuffer inputBuffer = inputBuffers[bufferIndex];
                inputBuffer.clear();
                inputBuffer.put(data, 0, data.length);
                //nv21转换格式
//                convertor.convert(data, inputBuffers[bufferIndex],Constans.RTMP_WIDTH,Constans.RTMP_HEIGHT);
//                convertor.convert(data, inputBuffer);
                mediaCodec.queueInputBuffer(bufferIndex, 0, inputBuffers[bufferIndex].position(), now, 0);

                MediaCodec.BufferInfo mBufferInfo = new MediaCodec.BufferInfo();
                int outputBufferIndex = mediaCodec.dequeueOutputBuffer(mBufferInfo, 0);
                while (outputBufferIndex >= 0) {
                    ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
                    Sender.getInstance().rtmpSend(mBufferInfo, outputBuffer);
                    mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
                    outputBufferIndex = mediaCodec.dequeueOutputBuffer(mBufferInfo, 0);
                }
            } else if (bufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                Log.e(TAG, "INFO_OUTPUT_FORMAT_CHANGED: ");
                MediaFormat newFormat = mediaCodec.getOutputFormat();
                Sender.getInstance().rtmpSendFormat(newFormat);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    private MediaCodecInfo selectCodec(String mimeType) {
        int numCodecs = MediaCodecList.getCodecCount();
        for (int i = 0; i < numCodecs; i++) {
            MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
            //是否是编码器
            if (!codecInfo.isEncoder()) {
                continue;
            }
            String[] types = codecInfo.getSupportedTypes();
            Log.e(TAG, "Arrays.toString(types): " + Arrays.toString(types));
            for (String type : types) {
                Log.e(TAG, "equal: " + mimeType.equalsIgnoreCase(type));
                if (mimeType.equalsIgnoreCase(type)) {
                    Log.e(TAG, "codecInfo " + codecInfo.getName());
                    return codecInfo;
                }
            }
        }
        return null;
    }
    //yv12 转 yuv420p  yvu -> yuv
    private void swapYV12toI420(byte[] yv12bytes, byte[] i420bytes, int width, int height)
    {
        System.arraycopy(yv12bytes, 0, i420bytes, 0,width*height);
        System.arraycopy(yv12bytes, width*height+width*height/4, i420bytes, width*height,width*height/4);
        System.arraycopy(yv12bytes, width*height, i420bytes, width*height+width*height/4,width*height/4);
    }

}
